﻿using FastCodeGeneration.Core.Framework;
using FastCodeGeneration.Entity;
using FastCodeGeneration.IRepository;
using FastCodeGeneration.IService;
using FastCodeGeneration.Utility;
using SqlSugar;

namespace FastCodeGeneration.Service
{
    public class ProjectService : BaseServices<IProjectRepository, Project>, IProjectService
    {

        private readonly ICodeGeneratorRepository codeGeneratorRepository;

        private readonly ITableRepository tableRepository;

        private readonly ITableColumnRepository tableColumnRepository;

        private readonly ITemplateRepository templateRepository;

        private readonly IModuleRepository moduleRepository;


        public ProjectService(IProjectRepository projectRepository,
            ICodeGeneratorRepository codeGeneratorRepository,
            ITableRepository tableRepository,
            ITableColumnRepository tableColumnRepository,
            ITemplateRepository templateRepository,
            IModuleRepository moduleRepository) : base(projectRepository)
        {
            this.codeGeneratorRepository = codeGeneratorRepository;
            this.tableRepository = tableRepository;
            this.tableColumnRepository = tableColumnRepository;
            this.templateRepository = templateRepository;
            this.moduleRepository = moduleRepository;
        }

        /// <summary>
        /// 同步数据表和字段
        /// </summary>
        /// <param name="projectId">项目id</param>
        /// <returns></returns>
        public bool Pull(int projectId)
        {
            var project = SelectById(projectId);
            var moduleList = moduleRepository.SelectByProjectId(projectId);
            var dbTables = codeGeneratorRepository.GetDbTables(project);
            var insertTables = new List<Table>();
            var insertTableColumns = new List<TableColumn>();

            var updateTables = new List<Table>();
            var updateTableColumns = new List<TableColumn>();

            var existentTables = tableRepository.GetTablesByProjectId(projectId);
            var existentColumns = tableColumnRepository.GetColumnsByProjectId(projectId);

            foreach (var table in dbTables)
            {
                var existentTable = existentTables.FirstOrDefault(e => e.Name == table.Name);
                Table entity = existentTable != null ? existentTable : new Table();
                entity.ProjectId = projectId;
                entity.Name = table.Name;
                entity.Description = table.Description;
                entity.ClassName = table.Name.LineToHump();
                entity.FieldClassName = table.Name.LineToHump().ToLowerCamelCase();
                var arr = table.Name.Split('_');
                entity.Prefix = arr[0];
                entity.ModuleName = entity.Prefix.ToLower();
                var module = moduleList.FirstOrDefault(e => e.TablePrefix == entity.Prefix);
                if (module != null)
                {
                    entity.ModuleName = module.Name;
                    if (module.FileIgnorePrefix)
                    {
                        var name = string.Join('_', arr.Skip(1));
                        entity.ClassName = name.LineToHump();
                        entity.FieldClassName = name.LineToHump().ToLowerCamelCase();
                    }
                }

                if (entity.Id != null)
                    updateTables.Add(entity);
                else
                    insertTables.Add(entity);

                var dbColumns = codeGeneratorRepository.GetDbTablesColumns(table.Name, project);
                foreach (DbColumnInfo dbColumn in dbColumns)
                {
                    var existentColumn = existentColumns.FirstOrDefault(e => e.TableName == table.Name && e.Name == dbColumn.DbColumnName);
                    TableColumn entityColumn = existentColumn != null ? existentColumn : new TableColumn();
                    entityColumn.ProjectId = projectId;
                    entityColumn.Name = dbColumn.DbColumnName;
                    entityColumn.TableName = dbColumn.TableName;
                    entityColumn.Description = dbColumn.ColumnDescription;
                    entityColumn.ColumnType = dbColumn.DataType;
                    entityColumn.FieldName = dbColumn.DbColumnName.LineToHump().ToLowerCamelCase();
                    entityColumn.Length = dbColumn.Length;
                    entityColumn.DecimalDigits = dbColumn.DecimalDigits;
                    entityColumn.Scale = dbColumn.Scale;
                    entityColumn.IsPrimaryKey = dbColumn.IsPrimarykey;
                    entityColumn.IsIdentity = dbColumn.IsIdentity;
                    entityColumn.IsRequired = !dbColumn.IsNullable;
                    entityColumn.FieldType = this.GetFieldType(project, entityColumn);
                    if (entityColumn.Id == null)
                    {
                        entityColumn.IsInsert = true;
                        entityColumn.IsEdit = true;
                        entityColumn.IsList = true;
                        entityColumn.IsQuery = true;
                        entityColumn.QueryType = "=";
                        entityColumn.HtmlType = "";
                        entityColumn.DictType = "String";
                        entityColumn.Sort = 0;
                    }

                    if (entityColumn.Id != null)
                        updateTableColumns.Add(entityColumn);
                    else
                        insertTableColumns.Add(entityColumn);
                }
            }

            tableRepository.BatchInsert(insertTables);
            tableColumnRepository.BatchInsert(insertTableColumns);

            tableRepository.BatchUpdate(updateTables);
            tableColumnRepository.BatchUpdate(updateTableColumns);

            return true;
        }

        private string GetFieldType(Project project, TableColumn column)
        {
            if (project.ServerTemplate == "JAVA")
            {
                if ("tinyint,smallint,mediumint,int,integer".Contains(column.ColumnType.ToLower()))
                {
                    return "Integer";
                }
                else if ("char,varchar,tinytext,text,mediumtext,longtext".Contains(column.ColumnType.ToLower()))
                {
                    return "String";
                }
                else if ("date,datetime,timestamp".Contains(column.ColumnType.ToLower()))
                {
                    return "Date";
                }
                else if (column.ColumnType.ToLower() == "bigint")
                {
                    return "Long";
                }
                else if (column.ColumnType.ToLower() == "bit")
                {
                    return "Boolean";
                }
                else if (column.ColumnType.ToLower() == "float")
                {
                    return "Float";
                }
                else if (column.ColumnType.ToLower() == "double")
                {
                    return "Double";
                }
                else if (column.ColumnType.ToLower() == "decimal")
                {
                    return "BigDecimal";
                }

                return "String";

            }
            if (project.ServerTemplate == "CSharp")
            {
                if ("tinyint,smallint,mediumint,int,integer".Contains(column.ColumnType.ToLower()))
                {
                    return "int";
                }
                else if ("char,varchar,tinytext,text,mediumtext,longtext".Contains(column.ColumnType.ToLower()))
                {
                    return "string";
                }
                else if ("date,datetime,timestamp".Contains(column.ColumnType.ToLower()))
                {
                    return "DateTime";
                }
                else if (column.ColumnType.ToLower() == "bigint")
                {
                    return "Long";
                }
                else if (column.ColumnType.ToLower() == "bit")
                {
                    return "bool";
                }
                else if (column.ColumnType.ToLower() == "float")
                {
                    return "float";
                }
                else if (column.ColumnType.ToLower() == "double")
                {
                    return "double";
                }
                else if (column.ColumnType.ToLower() == "decimal")
                {
                    return "decimal";
                }

                return "String";
            }

            return string.Empty;
        }


        public bool SaveProject(Project entity)
        {
            if (entity == null)
            {
                return false;
            }
            this.Save(entity);
            templateRepository.DeleteByProjectId(entity.Id);

            List<Template> defaultTemplates = templateRepository.SelectDefault(entity.ServerTemplate, entity.ViewTemplate);
            defaultTemplates.ForEach(template =>
            {
                template.Id = null;
                template.ProjectId = entity.Id;
            });
            templateRepository.BatchInsert(defaultTemplates);
            return true;
        }



    }
}
